﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Metro.Kashikoi.ServiceContract.Location;
using Metro.Kashikoi.ServiceContract.Item;
using Metro.Kashikoi.ServiceContract.Storage;
using Metro.Kashikoi.Web.ViewModels;
using Metro.Kashikoi.ServiceContract;
using Metro.Kashikoi.Common.ExceptionHandling;
using System.ComponentModel;
using System.Data.Entity.Validation;

namespace Metro.Kashikoi.Web.Controllers
{
    public class LocationController : Controller
    {
        ILocationService locService = ServiceBus.GetService<ILocationService>();
        IItemService itemService = ServiceBus.GetService<IItemService>();
        ICategoryService catService = ServiceBus.GetService<ICategoryService>();
        IStorageService storageService = ServiceBus.GetService<IStorageService>();
        Organization _org;

        //
        // GET: /Location/Root
        public ActionResult Root()
        {
            LocationRootModel rootModel = new LocationRootModel();
            try
            {
                rootModel.Organization = GetOrganization();
            }
            catch (NotExistException)
            {
                Organization root = new Organization { Name = "System", Address = new Address { City = "Xi'an", PostalCode = "12345", State = "Shaanxi", Street = "Keji" } };
                locService.CreateOrganization(root);

                rootModel.Organization = GetOrganization();
            }
            var areaIds = from fac in rootModel.Organization.Facilities
                          from unit in fac.Units
                          from area in unit.StockAreas
                          select area.Id;

            rootModel.Inventories = ConvertToInventoryListViewModel(storageService.GetInventoriesOfStockAreas(areaIds));// new List<InventoryListItemViewModel>();// ConvertToInventoryListViewModel(FakeData.Inventories);
            return View(rootModel);
        }

        // Post: /Location/RenameRoot
        [HttpPost]
        public ActionResult RenameRoot(string rootName)
        {
            var org = GetOrganization();
            org.Name = rootName;
            locService.UpdateOrganization(org);
            return RedirectToAction("Root");
        }

        // Post: /Location/AddFacility
        [HttpPost]
        public ActionResult AddFacility(string facilityName)
        {
            Address newAddress = new Address { City = "", PostalCode = "12345", State = "", Street = "" };
            var newFacility = new Facility { Name = facilityName, WindowsGroup = "", Address = newAddress };
            var org = GetOrganization();
            var createdFacility = locService.CreateFacility(newFacility, org.Id);

            return RedirectToAction("Facility", new { id = createdFacility.Id });
        }

        // GET: /Location/Facility/5
        public ActionResult Facility(int id)
        {
            LocationFacilityModel facilityModel = new LocationFacilityModel();
            facilityModel.Organization = GetOrganization();
            facilityModel.CurrentFacility = facilityModel.Organization.Facilities.Single(f => f.Id == id);

            var areaIds = from unit in facilityModel.CurrentFacility.Units
                          from area in unit.StockAreas
                          select area.Id;
            var invs = storageService.GetInventoriesOfStockAreas(areaIds);
            facilityModel.Inventories = ConvertToInventoryListViewModel(invs);

            return View(facilityModel);
        }

        // Post: /Location/RenameFacility
        [HttpPost]
        public ActionResult RenameFacility(int facilityId, string facilityName)
        {
            var org = GetOrganization();
            var curFacility = org.Facilities.Single(f => f.Id == facilityId);
            curFacility.Name = facilityName;
            locService.UpdateFacility(curFacility);

            return RedirectToAction("Facility", new { id = facilityId });
        }

        //Post: /Location/AddUnit
        [HttpPost]
        public ActionResult AddUnit(int facilityId, string unitName)
        {
            var newUnit = new Unit { Name = unitName };
            var createdUnit = locService.CreateUnit(newUnit, facilityId);

            return RedirectToAction("Unit", new { id = createdUnit.Id });
        }

        // GET: /Location/Unit/5
        public ActionResult Unit(int id)
        {
            LocationUnitModel unitModel = new LocationUnitModel();
            unitModel.Organization = GetOrganization();
            var curUnit = (from fac in unitModel.Organization.Facilities
                           from unit in fac.Units
                           where unit.Id == id
                           select unit).First();
            unitModel.CurrentUnit = curUnit;

            var areaIds = from area in curUnit.StockAreas
                          select area.Id;

            unitModel.Inventories = ConvertToInventoryListViewModel(storageService.GetInventoriesOfStockAreas(areaIds));

            return View(unitModel);
        }

        //Post: /Location/RenameUnit
        [HttpPost]
        public ActionResult RenameUnit(int unitId, string unitName)
        {
            var org = GetOrganization();
            var curUnit = (from fac in org.Facilities
                           from unit in fac.Units
                           where unit.Id == unitId
                           select unit).First();
            curUnit.Name = unitName;
            locService.UpdateUnit(curUnit);

            return RedirectToAction("Unit", new { id = unitId });
        }

        [HttpPost]
        public ActionResult AddStockArea(int unitId, string stockAreaName)
        {
            var newArea = new StockArea { Name = stockAreaName };
            var createdArea = locService.CreateStockArea(newArea, unitId);

            return RedirectToAction("StockArea", new { id = createdArea.Id });
        }

        // GET: /Location/StockArea/5
        public ActionResult StockArea(int id)
        {
            LocationStockAreaModel stockAreaModel = new LocationStockAreaModel();
            var org = GetOrganization();
            stockAreaModel.Organization = org;
            var curStockArea = (from fac in org.Facilities
                                from unit in fac.Units
                                from area in unit.StockAreas
                                where area.Id == id
                                select area).Single();
            stockAreaModel.CurrentStockArea = curStockArea;
            var binInventories = storageService.GetInventoriesOfStockArea(id);
            stockAreaModel.Inventories = ConvertToInventoryListViewModel(binInventories); // new List<InventoryListItemViewModel>();// ConvertToInventoryListViewModel(FakeData.Inventories.Where(inv => inv.StockAreaId == id));

            return View(stockAreaModel);
        }

        [HttpPost]
        public ActionResult RenameStockArea(int stockAreaId, string stockAreaName)
        {
            var org = GetOrganization();
            var curStockArea = (from fac in org.Facilities
                                from unit in fac.Units
                                from area in unit.StockAreas
                                where area.Id == stockAreaId
                                select area).Single();
            curStockArea.Name = stockAreaName;
            locService.UpdateStockArea(curStockArea);

            return RedirectToAction("StockArea", new { id = stockAreaId });
        }

        //Get /Location/MapStockItem/5, id refers to the stockroom id
        public ActionResult MapStockItem(int id)
        {
            var org = GetOrganization();
            var curStockArea = (from fac in org.Facilities
                                from unit in fac.Units
                                from area in unit.StockAreas
                                where area.Id == id
                                select area).Single();

            ViewBag.StockArea = curStockArea;
            ViewBag.Items = itemService.GetAllItems();
            ViewBag.Categories = catService.GetAllCategories();

            BinInventory newInv = new BinInventory { StockAreaId = id };

            return View(newInv);
        }

        //Post /Location/MapStockItem/5, id refers to the stockroom id
        [HttpPost]
        public ActionResult MapStockItem(BinInventory binInv, FormCollection formData)
        {
            binInv.CategoryId = int.Parse(formData["categoryList"]);
            binInv.ItemId = int.Parse(formData["itemList"]);
            binInv.Trigger = new DoorTrigger { Flip = 1, Inventory = binInv };
            binInv.Container = new LabeledShelfContainer { Label1 = "label1", Label2 = "label2", Label3 = "label3" };

            try
            {
                storageService.CreateInventory(binInv, binInv.StockAreaId);
            }
            catch (AppException ex)
            {
                var errors = ex.Message;

            }

            return RedirectToAction("StockArea", new { id = binInv.StockAreaId });
        }

        //Get /Location/MapStockItem/5
        public ActionResult EditStockItemMap(int id)
        {
            var inv = storageService.GetInventoryById(id);
            return View(inv);
        }

        //Get /Location/MapStockItem/5
        [HttpPost]
        public ActionResult EditStockItemMap(BinInventory modified)
        {

            storageService.UpdateInventory(modified);
            return RedirectToAction("StockArea", new { id = modified.StockAreaId });
        }

        public ActionResult DeleteStockItemMap(int id)
        {
            var inv = storageService.GetInventoryById(id);
            storageService.DeleteInventory(inv.Id);
            return RedirectToAction("StockArea", new { id = inv.StockAreaId });
        }

        private List<InventoryListItemViewModel> ConvertToInventoryListViewModel(IEnumerable<BinInventory> list)
        {
            var org = GetOrganization();

            var inventoryViewModel = list.Select(inv =>
            {
                var viewModel = new InventoryListItemViewModel(inv);
                viewModel.StockArea = (from fac in org.Facilities
                                       from unit in fac.Units
                                       from area in unit.StockAreas
                                       where area.Id == inv.StockAreaId
                                       select area).Single();

                viewModel.Item = itemService.GetItem(inv.ItemId);
                viewModel.Category = catService.GetCategory(inv.CategoryId);

                return viewModel;
            });

            return inventoryViewModel.ToList();
        }

        private InventoryListItemViewModel ConvertToInventoryListViewModel(BinInventory binInv)
        {
            var result = new InventoryListItemViewModel(binInv);

            result.StockArea = (from fac in GetOrganization().Facilities
                                from unit in fac.Units
                                from area in unit.StockAreas
                                where area.Id == binInv.Id
                                select area).Single();
            result.Item = itemService.GetItem(binInv.ItemId);
            result.Category = catService.GetCategory(binInv.CategoryId);

            return result;
        }

        private Organization GetOrganization()
        {
            if (_org == null) _org = locService.GetDefaultOrganization();
            return _org;
        }
    }
}
